using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Globalization;
using System.Linq;

namespace LINQPadDriverHelper
{
  internal class SqlCommandFormatter1 : CommandFormatter1
  {
    private string GetDeclaration(SqlParameter p)
    {
      string str1 = p.SqlDbType==SqlDbType.Text
        ? "VarChar"
        : (p.SqlDbType==SqlDbType.NText
          ? "NVarChar"
          : (p.SqlDbType==SqlDbType.Image ? "VarBinary" : ((object) p.SqlDbType).ToString()));
      string str2 = "DECLARE " + p.ParameterName + " " + str1;
      switch (p.SqlDbType) {
        case SqlDbType.Binary:
        case SqlDbType.Char:
        case SqlDbType.Image:
        case SqlDbType.NChar:
        case SqlDbType.NText:
        case SqlDbType.NVarChar:
        case SqlDbType.Text:
        case SqlDbType.VarBinary:
        case SqlDbType.VarChar:
          return string.Concat(new object[] {str2, "(", Math.Min(1000, Math.Max(1, p.Size)), ")"});
        case SqlDbType.Decimal:
          if (p.Value==null || p.Value is DBNull)
            return str2 + "(1,0)";
          string str3 = p.Value.ToString();
          return str2 + (object) "(" + (string) (object) (str3.Length + p.Scale) + "," + (string) (object) p.Scale + ")";
        default:
          return str2;
      }
    }

    private string GetNativeValue(SqlParameter p)
    {
      if (p.Value==null || p.Value is DBNull)
        return "null";
      object obj = p.Value;
      if (IsNumeric(obj.GetType()))
        return string.Format(CultureInfo.InvariantCulture, "{0}", new[] {obj});
      if (obj is bool)
        return (bool) obj ? "1" : "0";
      if (obj is DateTime || obj is DateTimeOffset) {
        string str = "yyyy-MM-dd";
        if (p.SqlDbType!=SqlDbType.Date) {
          str = str + " HH:mm:ss";
          if (p.SqlDbType!=SqlDbType.SmallDateTime) {
            str = str + ".fff";
            if (p.SqlDbType==SqlDbType.DateTime2 || p.SqlDbType==SqlDbType.DateTimeOffset)
              str = str + "ffff";
          }
        }
        if (obj is DateTimeOffset)
          str = str + "zzz";
        // ReSharper disable once FormatStringProblem
        return "'" + string.Format(CultureInfo.InvariantCulture, "{0:" + str + "}", new[] {obj}) + "'";
      }
      if (obj is TimeSpan)
        return "'" + string.Format(CultureInfo.InvariantCulture, "{0}'", new[] {obj});
      var numArray = obj as byte[];
      if (numArray != null)
      {
        var chArray1 = new char[numArray.Length * 2];
        int num1 = 0;
        foreach (byte num2 in numArray) {
          string str = num2.ToString("X2");
          char[] chArray2 = chArray1;
          int index1 = num1;
          const int num3 = 1;
          int num4 = index1 + num3;
          var num5 = (int) str[0];
          chArray2[index1] = (char) num5;
          char[] chArray3 = chArray1;
          int index2 = num4;
          const int num6 = 1;
          num1 = index2 + num6;
          var num7 = (int) str[1];
          chArray3[index2] = (char) num7;
          if (num1 >= 500)
            return "0x" + (object) new string(chArray1) + " -- (first 500 bytes/" + (string) (object) numArray.Length +
              " shown)";
        }
        return "0x" + new string(chArray1);
      }
      if (obj is char || obj is string) {
        string str1 = obj.ToString();
        int length = str1.Length;
        bool flag = length > 1000;
        if (flag)
          str1 = str1.Substring(0, 997) + "...";
        string str2 = "'" + str1.Replace("'", "''") + "'";
        if (flag)
          str2 = string.Concat(new object[] {str2, " -- (first 1000 characters/", length, " shown)"});
        if (str2.Any(c => (int) c < 31 || (int) c > (int) sbyte.MaxValue))
          str2 = "N" + str2;
        return str2;
      }
      if (obj is Guid)
        return "'" + obj + "'";
      return string.Format(CultureInfo.InvariantCulture, "{0}", new[] {obj});
    }

    #region Non-public methods

    protected override string GetInitializer(DbParameter parameter)
    {
      var p = (SqlParameter) parameter;
      string str = GetDeclaration(p);
      if (p.Direction==ParameterDirection.Input || p.Direction==ParameterDirection.InputOutput) {
        //if (LINQPadSession.SqlDriver.CoreServerInfo.ServerVersion.Major < 10)
        str = str + " SET " + p.ParameterName;
        str = str + " = " + GetNativeValue(p);
      }
      return str;
    }

    #endregion
  }
}